package com.mls.guardian.executor.master;

import com.mls.guardian.common.RemoteUtil;
import com.mls.guardian.container.MasterContainer;
import com.mls.guardian.dataobj.ServerProcessInfo;
import com.mls.guardian.protocol.RemoteBody;
import com.mls.guardian.protocol.RemoteCommand;
import com.mls.guardian.protocol.body.AppRestartBody;
import com.mls.guardian.remoting.executor.RemoteExecutor;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by jl on 15/9/17.
 */
public class RestartAppExecutor implements RemoteExecutor {
    private static final Logger log = LoggerFactory.getLogger(RestartAppExecutor.class);
    private MasterContainer container;
    private Lock restartLock = new ReentrantLock();

    public RestartAppExecutor(MasterContainer container) {
        this.container = container;
    }

    @Override
    public RemoteBody execute(ChannelHandlerContext ctx, RemoteCommand request) throws Exception {
        AppRestartBody response = new AppRestartBody();

        if (restartLock.tryLock()) {
            try {
                List<Future<RemoteBody>> futures = new ArrayList<>();

                AppRestartBody appRestart = (AppRestartBody) request.getRemoteBody();
                List<ServerProcessInfo> serverList = appRestart.getServerProcessInfoListList();

                if (appRestart.getVersionTag() == null || appRestart.getVersionTag().length() == 0) {
                    //appRestart.setErrorContent("VersionTag未指定");
                    final String DATE_FORMAT = "yyyyMMdd_HH-mm-ss-SSS";
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
                    String versionTag = simpleDateFormat.format(new Date(System.currentTimeMillis()));
                    appRestart.setVersionTag(versionTag);

                    request.setRemoteBody(appRestart);
                    response.setVersionTag(versionTag);
                } else {
                    response.setVersionTag(appRestart.getVersionTag());
                }

                //重起MASTER上面
                List clientAddrs = new ArrayList();
                for (ServerProcessInfo serverInfo : serverList) {
                    if (serverInfo.getIp().equals(RemoteUtil.getLocalHostIP())) {
                        futures.add(container.getServiceExecutor().submit(new Callable<RemoteBody>() {
                            @Override
                            public RemoteBody call() throws Exception {
                                AppRestartBody appRestartBody = container.restartApp(appRestart.getProjectName(), serverInfo.getProcessList(), appRestart.getVersionTag());
                                response.setVersion(appRestartBody.getVersion());
                                log.info("master 重启结束 返回");
                                return appRestartBody;
                            }
                        }));
                    } else {
                        clientAddrs.add(serverInfo.getIp());
                    }
                }

                //重起SLAVE上面
                List<Future<RemoteBody>> clientFutures = container.getClientDispatch()
                        .sendRequestToClientsByThreadPools(request, null, -1, container.getServiceExecutor());
                futures.addAll(clientFutures);


                for (Future<RemoteBody> future : futures) {
                    AppRestartBody responseFuture = (AppRestartBody) future.get();

                    if (!responseFuture.isSuc()) {
                        return responseFuture;
                    }
                }

                response.setSuc(true);
            } finally {
                restartLock.unlock();
            }
        } else {
            response.setSuc(false);
            response.setErrorContent("正在执行restart请等待完成后再发送请求");
        }


        return response;
    }
}
